package com.apex.shared.core.utils;

import lombok.experimental.UtilityClass;
import org.springframework.util.DigestUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * 文件操作工具类
 *
 * @author MoNaiHui
 */
@UtilityClass
public class FileUtils  {

    /**
     * 常用文件后缀
     */
    public static final String SUFFIX_TXT = ".txt";
    public static final String SUFFIX_JSON = ".json";
    public static final String SUFFIX_XML = ".xml";
    public static final String SUFFIX_PDF = ".pdf";
    public static final String SUFFIX_DOC = ".doc";
    public static final String SUFFIX_DOCX = ".docx";
    public static final String SUFFIX_XLS = ".xls";
    public static final String SUFFIX_XLSX = ".xlsx";
    public static final String SUFFIX_ZIP = ".zip";
    public static final String SUFFIX_RAR = ".rar";
    public static final String SUFFIX_7Z = ".7z";

    /**
     * 文件大小单位
     */
    public static final long KB = 1024L;
    public static final long MB = KB * 1024L;
    public static final long GB = MB * 1024L;
    public static final long TB = GB * 1024L;

    // ---------------------- 文件基本操作 ----------------------

    /**
     * 创建文件
     */
    public static boolean createFile(String filePath) throws IOException {
        File file = new File(filePath);
        if (file.exists()) {
            return false;
        }
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        return file.createNewFile();
    }

    /**
     * 创建目录
     */
    public static boolean createDirectory(String dirPath) {
        File dir = new File(dirPath);
        if (dir.exists()) {
            return false;
        }
        return dir.mkdirs();
    }

    /**
     * 删除文件
     */
    public static boolean deleteFile(String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            return false;
        }
        return file.delete();
    }

    /**
     * 删除目录（递归）
     */
    public static boolean deleteDirectory(String dirPath) {
        File dir = new File(dirPath);
        if (!dir.exists()) {
            return false;
        }
        if (!dir.isDirectory()) {
            return false;
        }
        File[] files = dir.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    deleteDirectory(file.getAbsolutePath());
                } else {
                    file.delete();
                }
            }
        }
        return dir.delete();
    }

    /**
     * 复制文件
     */
    public static void copyFile(String sourcePath, String targetPath) throws IOException {
        Files.copy(Paths.get(sourcePath), Paths.get(targetPath), StandardCopyOption.REPLACE_EXISTING);
    }

    /**
     * 移动文件
     */
    public static void moveFile(String sourcePath, String targetPath) throws IOException {
        Files.move(Paths.get(sourcePath), Paths.get(targetPath), StandardCopyOption.REPLACE_EXISTING);
    }

    // ---------------------- 文件读写操作 ----------------------

    /**
     * 读取文本文件内容
     */
    public static String readText(String filePath) throws IOException {
        return new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);
    }

    /**
     * 读取文本文件内容（按行）
     */
    public static List<String> readLines(String filePath) throws IOException {
        return Files.readAllLines(Paths.get(filePath), StandardCharsets.UTF_8);
    }

    /**
     * 写入文本内容到文件
     */
    public static void writeText(String filePath, String content) throws IOException {
        Files.write(Paths.get(filePath), content.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 追加文本内容到文件
     */
    public static void appendText(String filePath, String content) throws IOException {
        Files.write(Paths.get(filePath), content.getBytes(StandardCharsets.UTF_8), 
            StandardOpenOption.CREATE, StandardOpenOption.APPEND);
    }

    // ---------------------- 文件信息获取 ----------------------

    /**
     * 获取文件大小
     */
    public static long getFileSize(String filePath) {
        return new File(filePath).length();
    }

    /**
     * 获取文件扩展名
     */
    public static String getFileExtension(String fileName) {
        int dotIndex = fileName.lastIndexOf('.');
        return (dotIndex == -1) ? "" : fileName.substring(dotIndex);
    }

    /**
     * 获取文件名（不含扩展名）
     */
    public static String getFileNameWithoutExtension(String fileName) {
        int dotIndex = fileName.lastIndexOf('.');
        return (dotIndex == -1) ? fileName : fileName.substring(0, dotIndex);
    }

    /**
     * 获取文件MD5值
     */
    public static String getFileMD5(String filePath) throws IOException {
        try (FileInputStream fis = new FileInputStream(filePath)) {
            return DigestUtils.md5DigestAsHex(fis);
        }
    }

    // ---------------------- 文件压缩解压 ----------------------

    /**
     * 压缩文件或目录
     */
    public static void zip(String sourcePath, String zipPath) throws IOException {
        Path sourceDir = Paths.get(sourcePath);
        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipPath))) {
            Files.walk(sourceDir)
                .filter(path -> !Files.isDirectory(path))
                .forEach(path -> {
                    ZipEntry zipEntry = new ZipEntry(sourceDir.relativize(path).toString());
                    try {
                        zos.putNextEntry(zipEntry);
                        Files.copy(path, zos);
                        zos.closeEntry();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                });
        }
    }

    /**
     * 解压ZIP文件
     */
    public static void unzip(String zipPath, String targetDir) throws IOException {
        try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipPath))) {
            ZipEntry zipEntry;
            while ((zipEntry = zis.getNextEntry()) != null) {
                Path targetPath = Paths.get(targetDir, zipEntry.getName());
                if (!zipEntry.isDirectory()) {
                    Files.createDirectories(targetPath.getParent());
                    Files.copy(zis, targetPath, StandardCopyOption.REPLACE_EXISTING);
                }
                zis.closeEntry();
            }
        }
    }

    // ---------------------- 文件类型判断 ----------------------

    /**
     * 是否为图片文件
     */
    public static boolean isImage(String fileName) {
        String ext = getFileExtension(fileName).toLowerCase();
        return ext.matches("\\.(jpg|jpeg|png|gif|bmp)$");
    }

    /**
     * 是否为视频文件
     */
    public static boolean isVideo(String fileName) {
        String ext = getFileExtension(fileName).toLowerCase();
        return ext.matches("\\.(mp4|avi|mov|wmv|flv|mkv)$");
    }

    /**
     * 是否为音频文件
     */
    public static boolean isAudio(String fileName) {
        String ext = getFileExtension(fileName).toLowerCase();
        return ext.matches("\\.(mp3|wav|wma|ogg|aac|flac)$");
    }

    /**
     * 是否为文档文件
     */
    public static boolean isDocument(String fileName) {
        String ext = getFileExtension(fileName).toLowerCase();
        return ext.matches("\\.(doc|docx|xls|xlsx|ppt|pptx|pdf|txt)$");
    }

    /**
     * 是否为压缩文件
     */
    public static boolean isArchive(String fileName) {
        String ext = getFileExtension(fileName).toLowerCase();
        return ext.matches("\\.(zip|rar|7z|tar|gz)$");
    }

    // ---------------------- 文件大小格式化 ----------------------

    /**
     * 格式化文件大小
     */
    public static String formatFileSize(long size) {
        if (size < KB) {
            return size + " B";
        } else if (size < MB) {
            return String.format("%.2f KB", (float) size / KB);
        } else if (size < GB) {
            return String.format("%.2f MB", (float) size / MB);
        } else if (size < TB) {
            return String.format("%.2f GB", (float) size / GB);
        } else {
            return String.format("%.2f TB", (float) size / TB);
        }
    }
} 